<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    .box1{width: 100px;height: 100px;background: red;position: absolute;left:0px;top:0;}
    .line{width: 1px;background: black;position: absolute;left:400px;top:0;height: 400px;}
  </style>
</head>
<body>
  <div class="box1"></div>
  <div class="line"></div>
</body>
<script>

  const box1 = document.querySelector(".box1");
  
  box1.onmouseover = function(){
    move(box1, {
      top: 3,
      left: 300
    });
  }


  // 封装缓冲运动：任意元素任意属性运动到任意目标
  function move(ele, obj){
    if(ele.t) return;
    ele.t = setInterval(()=>{
      // 假设：当前运动，默认在目标，那么需要立即清除计时器
      let state = true;
      // 遍历属性所在对象，获取到属性和对应目标
      for(let key in obj){
        let now = parseInt(getStyle(ele, key));
        let speed = (obj[key] - now) / 10;
        speed = speed < 0 ? Math.floor(speed) : Math.ceil(speed);
        ele.style[key] = now + speed + "px";
        // 只要有一个属性没到目标，一定不能清除计时器，阻止计时器的清除
        if(now !== obj[key]){
          state = false;
        }
      }
      // 检测是否阻止了计时器的清除，如果没有阻止清除，可以清除计时器
      if(state){
        clearInterval(ele.t);
      }
    }, 30);
  }

  // 问题：只要有一个属性到目标了，计时器就被清除了

  // 解决：  
  // 有一个属性到目标了，计时器不一定被清除
  // 假设：当前运动，默认在目标，那么需要立即清除计时器
  // 验证假设：只要有一个属性没到目标，一定不能清除计时器，阻止计时器的清除
  // 检测是否阻止了计时器的清除：如果没有阻止清除，可以清除计时器





  function getStyle(ele, attr){
    if(ele.currentStyle){
      return ele.currentStyle[attr];
    }else{
      return getComputedStyle(ele)[attr];
    }
  }




  
</script>
</html>